/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package search;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexableField;
import search.lucene.Query;

/**
 *
 * @author cosmin
 */
@WebServlet(name = "QueryServlet", urlPatterns = {"/query"})
public class QueryServlet extends HttpServlet {

    protected int _count = 0;
    protected String SESSION_RESULT = "search_session_result";
    protected String SESSION_QUERY = "search_session_query";
    protected boolean useCache = true;

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            boolean hasResponse = false;
            String text = request.getParameter("text");
            String page = request.getParameter("page");
            int pageNumber = 1;
            if (null != page) {
                try {
                    pageNumber = Integer.parseInt(page);
                    if (pageNumber < 0) {
                        pageNumber = 0;
                    }
                } catch (Exception ex) {
                }
            }
            long startTime = System.currentTimeMillis();
            double totalTime = -1;
            this._count = 0;
            JsonArray resultArray;
            if (this._hasStoredQuery(request)) {
                resultArray = this._getStoredResult(request, pageNumber);
            } else {
                resultArray = this._getQueryResult(request, pageNumber);
                long endTime = System.currentTimeMillis();
                totalTime = (endTime - startTime);
                totalTime = totalTime / 1000;
            }
            JsonObject result = new JsonObject();
            result.add("result", resultArray);
            result.addProperty("done", (this._count > 0 ? "1" : "0"));
            result.addProperty("pages", "" + (this._count / 25));
            result.addProperty("time", "" + totalTime);
            result.addProperty("items", "" + this._count);
            out.println(result.toString());
        }
    }

    protected String _getSessionQuery(HttpServletRequest request) {
        return "+" + request.getParameter("text");
    }

    protected boolean _hasStoredQuery(HttpServletRequest request) {
        if (!this.useCache) {
            return false;
        }
        try {
            HttpSession currentSession = request.getSession();
            String currentSessionQuery = (String) currentSession.getAttribute(this.SESSION_QUERY);
            String currentQuery = this._getSessionQuery(request);
            if (currentQuery.equalsIgnoreCase(currentSessionQuery)) {
                return true;
            }
        } catch (Exception ex) {
            Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }

    protected boolean _setStoredQuery(HttpServletRequest request) {
        if (!this.useCache) {
            return false;
        }
        try {
            HttpSession currentSession = request.getSession();
            currentSession.setAttribute(this.SESSION_QUERY, this._getSessionQuery(request));
        } catch (Exception ex) {
            Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    protected JsonArray _getStoredResult(HttpServletRequest request, int pageNumber) {
        JsonArray resultArray = new JsonArray();
        if (this.useCache) {
            try {
                HttpSession currentSession = request.getSession();
                List<Map<String, String>> documents = (List<Map<String, String>>) currentSession.getAttribute(this.SESSION_RESULT);
                this._count = documents.size();
                int startIndex = (pageNumber - 1) * 25;
                for (int i = 0; i < 25; i++) {
                    if (documents.size() > i + startIndex) {
                        Map<String, String> document = documents.get(i + startIndex);
                        JsonObject documentResult = new JsonObject();
                        for (String field : document.keySet()) {
                            String fieldName = field.replace("_", " ").trim();
                            documentResult.addProperty(fieldName, document.get(field).toString());
                        }
                        resultArray.add(documentResult);
                    }
                }
            } catch (Exception ex) {
                Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return resultArray;
    }

    protected boolean _setStoredResult(HttpServletRequest request, List<Map<String, String>> documents) {
        if (!this.useCache) {
            return false;
        }
        try {
            HttpSession currentSession = request.getSession();
            currentSession.setAttribute(this.SESSION_RESULT, documents);
            this._setStoredQuery(request);
        } catch (Exception ex) {
            Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    protected List<Map<String, String>> _convertDocumentsInMap(List<Document> documents) {
        List<Map<String, String>> result = new ArrayList<>();
        try {
            for (Document document : documents) {
                Map<String, String> doc = new HashMap<>();
                for (IndexableField field : document.getFields()) {
                    String fieldName = field.name().replace("_", " ").trim();
                    doc.put(fieldName, document.get(field.name()).toString());
                }
                result.add(doc);
            }
        } catch (Exception ex) {
            Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    protected JsonArray _getQueryResult(HttpServletRequest request, int pageNumber) {
        JsonArray resultArray = new JsonArray();
        try {
            String text = request.getParameter("text");
            if (null != text && !text.equalsIgnoreCase("")) {
                Query query = new Query();
                if (query.doSearch(text)) {
                    List<Document> docs = query.getDocuments();
                    List<Map<String, String>> documents = this._convertDocumentsInMap(docs);
                    this._count = documents.size();
                    int startIndex = (pageNumber - 1) * 25;
                    for (int i = 0; i < 25; i++) {
                        if (documents.size() > i + startIndex) {
                            Map<String, String> document = documents.get(i + startIndex);
                            JsonObject documentResult = new JsonObject();
                            for (String field : document.keySet()) {
                                String fieldName = field.replace("_", " ").trim();
                                documentResult.addProperty(fieldName, document.get(field).toString());
                            }
                            resultArray.add(documentResult);
                        }
                    }
                    this._setStoredResult(request, documents);
                }
                query.closeIndexer();
            }
        } catch (Exception ex) {
            Logger.getLogger(FiltreServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return resultArray;
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
